package de.codi;

import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Properties;


public class SettingsHandler
{
    public static CODISettingID loadSettings() throws FileNotFoundException, IOException
    {
        // Read properties file.
        Properties properties = new Properties();
        if(CODISettings.PATH_CS != null && CODISettings.PATH_CS.contains("codi.properties")) {
            properties.load(new FileInputStream(CODISettings.PATH_CS));
        } else {
            properties.load(new FileInputStream(CODISettings.PATH + "codi.properties"));
        }

        boolean overideSettings = Boolean.parseBoolean(properties.getProperty("overrideSettings", "false"));

        CODISettingID id = CODISettingID.AUTO;
        int track = -1;
        if(overideSettings) {
            CODISettings.overrideSettings = overideSettings;

            CODISettings.SIMPLE_THRESHOLD_DEFAULT = Double.parseDouble(properties.getProperty("SIMPLE_THRESHOLD_DEFAULT", Double.toString(CODISettings.SIMPLE_THRESHOLD_DEFAULT)));

            CODISettings.functionalOneToOneConstraint = Boolean.parseBoolean(properties.getProperty("functionalOneToOneConstraint", Boolean.toString(CODISettings.functionalOneToOneConstraint)));
            CODISettings.subsumptionCoherenceConstraint = Boolean.parseBoolean(properties.getProperty("subsumptionCoherenceConstraint", Boolean.toString(CODISettings.subsumptionCoherenceConstraint)));

            CODISettings.domainCoherenceConstraint = Boolean.parseBoolean(properties.getProperty("domainCoherenceConstraint", Boolean.toString(CODISettings.domainCoherenceConstraint)));
            CODISettings.rangeCoherenceConstraint = Boolean.parseBoolean(properties.getProperty("rangeCoherenceConstraint", Boolean.toString(CODISettings.rangeCoherenceConstraint)));
            CODISettings.subsumptionStabilityConstraint = Boolean.parseBoolean(properties.getProperty("subsumptionStabilityConstraint", Boolean.toString(CODISettings.subsumptionStabilityConstraint)));

            CODISettings.domainStabilityConstraint = Boolean.parseBoolean(properties.getProperty("domainStabilityConstraint", Boolean.toString(CODISettings.domainStabilityConstraint)));
            CODISettings.rangeStabilityConstraint = Boolean.parseBoolean(properties.getProperty("rangeStabilityConstraint", Boolean.toString(CODISettings.rangeStabilityConstraint)));

            CODISettings.subsumptionStabilityWeight = Double.parseDouble(properties.getProperty("subsumptionStabilityWeight", Double.toString(CODISettings.subsumptionStabilityWeight)));
            CODISettings.domainStabilityWeight = Double.parseDouble(properties.getProperty("domainStabilityWeight", Double.toString(CODISettings.domainStabilityWeight)));
            CODISettings.rangeStabilityWeight = Double.parseDouble(properties.getProperty("rangeStabilityWeight", Double.toString(CODISettings.rangeStabilityWeight)));

            CODISettings.jaroWinklerWeight = Double.parseDouble(properties.getProperty("jaroWinklerWeight", Double.toString(CODISettings.jaroWinklerWeight)));
            CODISettings.cosineWeight = Double.parseDouble(properties.getProperty("cosineWeight", Double.toString(CODISettings.cosineWeight)));
            CODISettings.levenstheinWeight = Double.parseDouble(properties.getProperty("levenstheinWeight", Double.toString(CODISettings.levenstheinWeight)));
            CODISettings.jaccardWeight = Double.parseDouble(properties.getProperty("jaccardWeight", Double.toString(CODISettings.jaccardWeight)));
            CODISettings.smithWatermanGotohWeight = Double.parseDouble(properties.getProperty("smithWatermanGotohWeight", Double.toString(CODISettings.smithWatermanGotohWeight)));
            CODISettings.overlapCoefficientWeight = Double.parseDouble(properties.getProperty("overlapCoefficientWeight", Double.toString(CODISettings.overlapCoefficientWeight)));
            CODISettings.jakobTimoWeight = Double.parseDouble(properties.getProperty("jakobTimoWeight", Double.toString(CODISettings.jakobTimoWeight)));
            CODISettings.preliminaryWeight = Double.parseDouble(properties.getProperty("preliminaryWeight", Double.toString(CODISettings.preliminaryWeight)));

            CODISettings.detectionLimit = Integer.parseInt(properties.getProperty("detectionLimit", Integer.toString(CODISettings.detectionLimit)));

            CODISettings.structuralFiller = Boolean.parseBoolean(properties.getProperty("structuralFiller", Boolean.toString(CODISettings.structuralFiller)));
            CODISettings.individualFiller = Boolean.parseBoolean(properties.getProperty("individualFiller", Boolean.toString(CODISettings.functionalOneToOneConstraint)));
            CODISettings.penaltyString = Boolean.parseBoolean(properties.getProperty("penaltyString", Boolean.toString(CODISettings.penaltyString)));
            CODISettings.preliminaryString = Boolean.parseBoolean(properties.getProperty("preliminaryString", Boolean.toString(CODISettings.preliminaryString)));

            CODISettings.mergerString = Integer.parseInt(properties.getProperty("mergerString", Integer.toString(CODISettings.mergerString)));
            if(CODISettings.mergerString != 0 && CODISettings.mergerString != 1) {
                CODISettings.mergerString = 0;
                System.err.println("CODI Settings: variable mergerString not correct -> selected weight merger.");
            }

            // stringFiller
            CODISettings.stringNotEqualsPenalty = Boolean.parseBoolean(properties.getProperty("stringNotEqualsPenalty", Boolean.toString(CODISettings.stringNotEqualsPenalty)));
            CODISettings.stringFillerCosine = Boolean.parseBoolean(properties.getProperty("stringFillerCosine", Boolean.toString(CODISettings.stringFillerCosine)));
            CODISettings.stringFillerJaccard = Boolean.parseBoolean(properties.getProperty("stringFillerJaccard", Boolean.toString(CODISettings.stringFillerJaccard)));
            CODISettings.stringFillerJaroWinkler = Boolean.parseBoolean(properties.getProperty("stringFillerJaroWinkler", Boolean.toString(CODISettings.stringFillerJaroWinkler)));
            CODISettings.stringFillerLevensthein = Boolean.parseBoolean(properties.getProperty("stringFillerLevensthein", Boolean.toString(CODISettings.stringFillerLevensthein)));
            CODISettings.stringFillerOverlapoverlapCoefficient = Boolean.parseBoolean(properties.getProperty("stringFillerOverlapoverlapCoefficient", Boolean.toString(CODISettings.stringFillerOverlapoverlapCoefficient)));
            CODISettings.stringFillerSmithWatermanGotoh = Boolean.parseBoolean(properties.getProperty("stringFillerSmithWatermanGotoh", Boolean.toString(CODISettings.stringFillerSmithWatermanGotoh)));
            CODISettings.stringFillerJakobTimo = Boolean.parseBoolean(properties.getProperty("stringFillerJakobTimo", Boolean.toString(CODISettings.stringFillerJakobTimo)));

            CODISettings.alcomoSimple = Boolean.parseBoolean(properties.getProperty("alcomoSimple", Boolean.toString(CODISettings.alcomoSimple)));
            CODISettings.alcomoTimeOut = Integer.parseInt(properties.getProperty("alcomoTimeOut", Integer.toString(CODISettings.alcomoTimeOut)));
            CODISettings.versionSettingSplitValue = Double.parseDouble(properties.getProperty("versionSettingSplitValue", Double.toString(CODISettings.versionSettingSplitValue)));

            track = Integer.parseInt(properties.getProperty("track", "-1"));

            switch(track) {
                case -1:
                    id = CODISettingID.AUTO;
                break;
                case 0:
                    id = CODISettingID.BIOMEDICAL;
                break;
                case 1:
                    id = CODISettingID.VERSION;
                break;
                case 2:
                    id = CODISettingID.STANDARD;
                break;
                case 3:
                    id = CODISettingID.NONE;
                break;
                default:
                    id = CODISettingID.AUTO;
                break;
            }
        }

        return id;
    }


    public static void main(String[] args) throws FileNotFoundException, IOException
    {
        switch(1) {
            case 1:
                List<Property> properties = new ArrayList<Property>();

                properties.add(new Property("overrideSettings", "false", ""));
                properties.add(new Property("track", "-1", "-1=auto-detect; 0=biomedicine, 1=version, 2=non-version, 3=no track (use all properties)"));
                properties.add(new Property("", "", ""));
                properties.add(new Property("SIMPLE_THRESHOLD_DEFAULT", Double.toString(CODISettings.SIMPLE_THRESHOLD_DEFAULT), "Default value for a simople threshold"));
                properties.add(new Property("", "", ""));
                properties.add(new Property("functionalOneToOneConstraint", Boolean.toString(CODISettings.functionalOneToOneConstraint), "Activate having a functional one-to-one alignment (rockit-part)"));
                properties.add(new Property("subsumptionCoherenceConstraint", Boolean.toString(CODISettings.subsumptionCoherenceConstraint), "Activate the subsumption coherence constraints (rockit-part)"));
                properties.add(new Property("domainCoherenceConstraint", Boolean.toString(CODISettings.domainCoherenceConstraint), "Activate the domain coherence constraints (rockit-part)"));
                properties.add(new Property("rangeCoherenceConstraint", Boolean.toString(CODISettings.rangeCoherenceConstraint), "Activate the range coherence constraints (rockit-part)"));
                properties.add(new Property("subsumptionStabilityConstraint", Boolean.toString(CODISettings.subsumptionStabilityConstraint), "Activate the subsumption stability constraints (rockit-part)"));
                properties.add(new Property("", "", ""));
                properties.add(new Property("domainStabilityConstraint", Boolean.toString(CODISettings.domainStabilityConstraint), "Activate the domain stability constraints (rockit-part)"));
                properties.add(new Property("rangeStabilityConstraint", Boolean.toString(CODISettings.rangeStabilityConstraint), "Activate the range stability constraints (rockit-part)"));
                properties.add(new Property("", "", ""));
                properties.add(new Property("subsumptionStabilityWeight", Double.toString(CODISettings.subsumptionStabilityWeight), "Weight for the subsumption stability constraints (rockit-part)"));
                properties.add(new Property("domainStabilityWeight", Double.toString(CODISettings.domainStabilityWeight), "Weight for the domain stability constraints (rockit-part)"));
                properties.add(new Property("rangeStabilityWeight", Double.toString(CODISettings.rangeStabilityWeight), "Weight for the range stability constraints (rockit-part)"));
                properties.add(new Property("", "", ""));
                properties.add(new Property("jaroWinklerWeight", Double.toString(CODISettings.jaroWinklerWeight), "Weight for Jaro Winkler (MatrixFiller)"));
                properties.add(new Property("cosineWeight", Double.toString(CODISettings.cosineWeight), "Weight for Cosine (MatrixFiller)"));
                properties.add(new Property("levenstheinWeight", Double.toString(CODISettings.levenstheinWeight), "Weight for Levensthein (MatrixFiller)"));
                properties.add(new Property("jaccardWeight", Double.toString(CODISettings.jaccardWeight), "Weight for Jaccard (MatrixFiller)"));
                properties.add(new Property("smithWatermanGotohWeight", Double.toString(CODISettings.smithWatermanGotohWeight), "Weight for Smith Waterman Gotoh (MatrixFiller)"));
                properties.add(new Property("overlapCoefficientWeight", Double.toString(CODISettings.overlapCoefficientWeight), "Weight for Overlap Coefficient (MatrixFiller)"));
                properties.add(new Property("jakobTimoWeight", Double.toString(CODISettings.jakobTimoWeight), "Weight for jakobTimo Coefficient (MatrixFiller)"));
                properties.add(new Property("preliminaryWeight", Double.toString(CODISettings.preliminaryWeight), "Preliminary (StringPreparation)"));
                properties.add(new Property("", "", ""));
                properties.add(new Property("detectionLimit", Integer.toString(CODISettings.detectionLimit), "Limit for Classes and Properties for track detection."));
                properties.add(new Property("", "", ""));
                properties.add(new Property("structuralFiller", Boolean.toString(CODISettings.structuralFiller), ""));
                properties.add(new Property("individualFiller", Boolean.toString(CODISettings.individualFiller), ""));
                properties.add(new Property("penaltyString", Boolean.toString(CODISettings.penaltyString), ""));
                properties.add(new Property("preliminaryString", Boolean.toString(CODISettings.preliminaryString), ""));
                properties.add(new Property("", "", ""));
                properties.add(new Property("mergerString", Integer.toString(CODISettings.mergerString), "Settings: 0: weight merger; 1: max merger"));
                properties.add(new Property("", "", ""));
                properties.add(new Property("stringNotEqualsPenalty", Boolean.toString(CODISettings.stringNotEqualsPenalty), ""));
                properties.add(new Property("stringFillerCosine", Boolean.toString(CODISettings.stringFillerCosine), ""));
                properties.add(new Property("stringFillerJaccard", Boolean.toString(CODISettings.stringFillerJaccard), ""));
                properties.add(new Property("stringFillerJaroWinkler", Boolean.toString(CODISettings.stringFillerJaroWinkler), ""));
                properties.add(new Property("stringFillerLevensthein", Boolean.toString(CODISettings.stringFillerLevensthein), ""));
                properties.add(new Property("stringFillerOverlapoverlapCoefficient", Boolean.toString(CODISettings.stringFillerOverlapoverlapCoefficient), ""));
                properties.add(new Property("stringFillerSmithWatermanGotoh", Boolean.toString(CODISettings.stringFillerSmithWatermanGotoh), ""));
                properties.add(new Property("stringFillerJakobTimo", Boolean.toString(CODISettings.stringFillerJakobTimo), ""));
                properties.add(new Property("", "", ""));
                properties.add(new Property("alcomoSimple", Boolean.toString(CODISettings.alcomoSimple), ""));
                properties.add(new Property("alcomoTimeOut", Integer.toString(CODISettings.alcomoTimeOut), ""));
                properties.add(new Property("", "", ""));
                properties.add(new Property("versionSettingSplitValue", Double.toString(CODISettings.versionSettingSplitValue), ""));
                properties.add(new Property("", "", ""));
                properties.add(new Property("PENALTY", Double.toString(CODISettings.PENALTY), "String not equals penalty"));
                properties.add(new Property("PENALTYSPACE", Double.toString(CODISettings.PENALTYSPACE), ""));
                properties.add(new Property("versionSettingSplitValue", Double.toString(CODISettings.versionSettingSplitValue), ""));
                properties.add(new Property("", "", ""));
                properties.add(new Property("MAXCHARACTER", Integer.toString(CODISettings.MAXCHARACTER), "words with more then 50 characters will be ignored"));
                properties.add(new Property("TOPVALUES", Integer.toString(CODISettings.TOPVALUES), "number of top values for the structural part"));
                properties.add(new Property("MAXWORDS", Integer.toString(CODISettings.MAXWORDS), "Strings with more then 6 Words will be ignored"));

                try {
                    BufferedWriter out = new BufferedWriter(new FileWriter("codi.properties"));
                    out.write("# CODI Settings\n");
                    out.write("# file generated on " + (new Date()).toString() + "\n\n");
                    for(Property p : properties) {
                        out.write(p.toString());
                    }
                    out.close();
                } catch(IOException e) {
                    System.out.println("Exception ");

                }

            break;
            case 2:
                // Read properties file.
                Properties trash = new Properties();
                trash.load(new FileInputStream("codi.properties"));
                for(Object o : trash.keySet()) {
                    String s = (String) o;
                    System.out.println(s + ":\t" + trash.getProperty(s));
                }
            break;
            case 3:
                System.out.println(loadSettings());
        }
    }
}



class Property
{
    private String key;
    private String value;
    private String comment;


    public Property(String key, String value, String comment)
    {
        this.key = key;
        this.value = value;
        this.comment = comment;
    }


    @Override
    public String toString()
    {
        StringBuilder sb = new StringBuilder(255);

        if(comment.length() > 0) {
            sb.append("# " + comment + "\n");
        }
        if(key.length() > 0 && value.length() > 0) {
            sb.append(key + " = " + value);
        }
        sb.append("\n");

        return sb.toString();
    }
}
